/*
 * Copyright (C) 2006-2007 Eskil Bylund
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

using System;

using Gtk;

using DCSharp.Backend.Managers;

namespace DCSharp.Gui
{
	public enum PageStyle
	{
		Tabs,
		List
	}

	public class PageEventArgs : EventArgs
	{
		private Page page;

		public PageEventArgs(Page page)
		{
			this.page = page;
		}

		public Page Page
		{
			get { return page; }
		}
	}

	/// <summary>
	/// An abstract base class for handling pages. 
	/// </summary>
	public abstract class PageManager : HBox
	{
		/// <summary>
		/// Raised when a page is added.
		/// </summary>
		public event EventHandler<PageEventArgs> PageAdded;

		/// <summary>
		/// Raised when a page is removed.
		/// </summary>
		public event EventHandler<PageEventArgs> PageRemoved;

		/// <summary>
		/// Raised when the current page changes.
		/// </summary>
		public event EventHandler<PageEventArgs> CurrentPageChanged;

		#region Properties

		/// <summary>
		/// Gets the number of pages handle by the PageManager.
		/// </summary>
		/// <value>The number of pages handled by the PageManager.</value>
		public abstract int Count
		{
			get;
		}

		/// <summary>
		/// Gets the current page.
		/// </summary>
		/// <value>The current page.</value>
		public abstract Page Current
		{
			get;
		}

		/// <summary>
		/// Gets the page at the specified index.
		/// </summary>
		/// <value>The page at the specified index.</value>
		public abstract Page this[int index]
		{
			get;
		}

		#endregion

		#region Methods

		/// <summary>
		/// Creates a new PageManager instance.
		/// </summary>
		/// <returns>A PageManager instance.</returns>
		public static PageManager Create(PageStyle style)
		{
			if (style == PageStyle.List)
			{
				return new PageManagerTree();
			}
			else
			{
				return new PageManagerNotebook();
			}
		}

		/// <summary>
		/// Adds a page to the PageManager.  
		/// </summary>
		/// <param name="page">The page to add.</param>
		public abstract void Add(Page page);

		/// <summary>
		/// Removes a page from the PageManager.
		/// </summary>
		/// <param name="page">The page to remove.</param>
		public abstract void Remove(Page page);

		/// <summary>
		/// Removes all pages from the PageManager.
		/// </summary>
		public virtual void Clear()
		{
			while (Count > 0)
			{
				Remove(this[0]);
			}
		}

		/// <summary>
		/// Determines whether a page is handled by the PageManager.
		/// </summary>
		/// <param name="page">The page to locate.</param>
		/// <returns>True if the page is handled by the PageManager; otherwise, false.</returns>
		public abstract bool Contains(Page page);

		/// <summary>
		/// Presents the page to the user.
		/// </summary>
		/// <param name="page">The page to present.</param>
		public abstract void Present(Page page);

		/// <summary>
		/// Searches for a page of type T that matches the conditions defined
		/// by the specified predicate.
		/// </summary>
		/// <param name="match">The delegate that defines the search conditions.</param>
		/// <returns>The first matching page, if found; otherwise, the default value for type T.</returns>
		public T Find<T>(Predicate<T> match) where T : Page
		{
			for (int i = 0; i < Count; i++)
			{
				T page = this[i] as T;
				if (page != null && match(page))
				{
					return page;
				}
			}
			return default(T);
		}

		/// <summary>
		/// Raises the PageAdded event.
		/// </summary>
		/// <param name="page">The page that's been added.</param>
		protected virtual void OnPageAdded(Page page)
		{
			if (PageAdded != null)
			{
				PageAdded(this, new PageEventArgs(page));
			}
		}

		/// <summary>
		/// Raises the PageRemoved event.
		/// </summary>
		/// <param name="page">The page that's been removed.</param>
		protected virtual void OnPageRemoved(Page page)
		{
			if (PageRemoved != null)
			{
				PageRemoved(this, new PageEventArgs(page));
			}
		}

		/// <summary>
		/// Raises the CurrentPageChanged event.
		/// </summary>
		/// <param name="page">The new current page.</param>
		protected virtual void OnCurrentPageChanged(Page page)
		{
			if (CurrentPageChanged != null)
			{
				CurrentPageChanged(this, new PageEventArgs(page));
			}
		}

		#endregion
	}
}
